package edu.mapi.aamas.uav;

import jade.core.Agent;
import jade.core.ProfileImpl;
import jade.core.Runtime;
import jade.wrapper.AgentController;
import jade.wrapper.ContainerController;

import java.util.Vector;

import javax.vecmath.Point3d;

import main.VehicleInterface;
import edu.mapi.aamas.behaviors.Navigation;
import edu.mapi.aamas.behaviors.SendState;
import edu.mapi.aamas.behaviors.TaskResponder;
import edu.mapi.aamas.common.MathCommons;
import edu.mapi.aamas.common.Proposal;
import edu.mapi.aamas.common.Task;
import edu.mapi.aamas.common.VehicleState;

/**
 * @author ZP
 */
public class UavAgent extends Agent {
	
	private static int counter = 1;
	
	private VehicleState state = new VehicleState();
	private double maxYaw = Math.toRadians(20); 
	//private double maxVel = 20;
	private double cruiseVel = 20;
	private double minVel = 5;
	private double litersSpeedRate = 0.1;
	private String id = "UAV"+(counter++);
	//private String model = "apv";
	private VehicleInterface myInterface = null;
	private Vector<Task> pendantTasks = new Vector<Task>();		
	
	public double timeToCompleteTask(Task task) {
		double accum = 0;
		Point3d prevPoint = state.getPoint();
		for (Task t : pendantTasks) {
			accum += timeAfter(prevPoint, accum, t);
			prevPoint = t.getLastPoint();
		}		
		
		accum += timeAfter(prevPoint, accum, task);		
		return accum;
	}		
	
	public double fuelAfterCompleteTask(Task task) {
		return state.getFuel() - (timeToCompleteTask(task) * litersSpeedRate * cruiseVel);
	}
	
	private double timeAfter(Point3d startPoint, double startTime, Task task) {
		double accum = 0;
		Point3d lastPoint = startPoint;
		for (Point3d pt : task.getPoints()) {
			accum += timeToReach(lastPoint, pt, cruiseVel);
			lastPoint = pt;
		}
		return accum;
	}
	
	private double timeToReach(Point3d start, Point3d destination, double velocity) {
		return MathCommons.distance(start, destination) / velocity;
	}
	
	public Proposal generateProposal(Task task) {		
		return new Proposal(task.getId(), getLocalName(), timeToCompleteTask(task), fuelAfterCompleteTask(task));
	}
	
	/**
	 * Agent's initialization
	 * @see Agent#setup()
	 */
	protected void setup() {
		super.setup();
		
		id = getLocalName();
		getPhysicalState().setId(id);
		getPhysicalState().setPoint(new Point3d(Math.random() * 300 - 150, Math.random() * 300 - 150, Math.random() * 10 + 5));
		getPhysicalState().setYaw(Math.random() * Math.PI * 2);
		
		Object[] args = getArguments();
		if (args.length >= 1)
			getPhysicalState().setModel(args[0].toString());
		else
			getPhysicalState().setModel("apv");
		
		try {
			if (args.length >= 2)
				cruiseVel = Double.parseDouble(args[1].toString());
			
			if (args.length >= 3)
				getPhysicalState().setFuel(Double.parseDouble(args[2].toString()));
			else
				getPhysicalState().setFuel(300 + Math.random() * 500);
			
			System.out.println("xxx");
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		

		addBehaviour(new Navigation(this, 333));
		addBehaviour(new SendState(this, 333));
		addBehaviour(new TaskResponder(this));
		myInterface = VehicleInterface.showInterface(this);
	}

	/**
	 * @param state the state to set
	 */
	public void setState(VehicleState state) {
		this.state = state;
	}

	/**
	 * @return the maxYaw
	 */
	public double getMaxYaw() {
		return maxYaw;
	}

	/**
	 * @param maxYaw the maxYaw to set
	 */
	public void setMaxYaw(double maxYaw) {
		this.maxYaw = maxYaw;
	}

	/**
	 * @return the cruiseVel
	 */
	public double getCruiseVel() {
		return cruiseVel;
	}

	/**
	 * @param cruiseVel the cruiseVel to set
	 */
	public void setCruiseVel(double cruiseVel) {
		this.cruiseVel = cruiseVel;
	}

	/**
	 * @return the minVel
	 */
	public double getMinVel() {
		return minVel;
	}

	/**
	 * @param minVel the minVel to set
	 */
	public void setMinVel(double minVel) {
		this.minVel = minVel;
	}

	/**
	 * @return the litersSpeedRate
	 */
	public double getLitersSpeedRate() {
		return litersSpeedRate;
	}

	/**
	 * @param litersSpeedRate the litersSpeedRate to set
	 */
	public void setLitersSpeedRate(double litersSpeedRate) {
		this.litersSpeedRate = litersSpeedRate;
	}

	/**
	 * @return the pendantTasks
	 */
	public Vector<Task> getPendantTasks() {
		return pendantTasks;
	}

	/**
	 * @return the state
	 */
	public VehicleState getPhysicalState() {
		return state;
	}
	
	
	public void stateUpdated() {
		myInterface.updateState(getPhysicalState());
	}
	
	
	public static void main(String[] args) throws Exception {
		ProfileImpl pi = new ProfileImpl();
		ContainerController cc = Runtime.instance().createMainContainer(new ProfileImpl());		
		AgentController uavContr = cc.createNewAgent("uav", UavAgent.class.getCanonicalName(), new Object[] {"test"});
		uavContr.start();
	}
}
